#include "mainwidget.h"
#include "./ui_mainwidget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QString>
#include <QLineEdit>
#include <QToolBar>

#include "model/datacenter.h"
#include "selfinfowidget.h"
#include "debug.h"
#include "sessionfriendarea.h"
#include "sessiondetailwidget.h"
#include "groupsessiondetailwidget.h"
#include "addfrienddialog.h"
#include "toast.h"

using namespace model;

MainWidget* MainWidget::instance = nullptr;

MainWidget *MainWidget::getInstance()
{
    if (instance == nullptr)
    {
        // 此处不传入参数，以桌面为父窗口
        // 由于此处的窗口是整个程序的主窗口，父窗口就设定为桌面，本身就是常规设定
        instance = new MainWidget();
    }
    return instance;
}

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MainWidget)
{
    ui->setupUi(this);

    this->setWindowTitle("WeChat");
    this->setWindowIcon(QIcon(":/resource/image/logo.png"));

    // 初始化主窗口的样式布局
    initMainWindow();
    // 初始化左侧窗口布局
    initLeftWindow();
    // 初始化中间窗口布局
    initMidWindow();
    // 初始化右侧窗口布局
    initRightWindow();
    // 初始化信号槽
    initSignalSlot();
    // 初始化 websocket
    initWebsocket();
}

MainWidget::~MainWidget()
{
    delete ui;
}

void MainWidget::initMainWindow()
{
    QHBoxLayout* layout = new QHBoxLayout();
    // Sapcing 就是 layout 内部元素之间的间隔距离，设为 0 就是 "紧挨着"
    layout->setSpacing(0);
    // layout 里面的元素距离四个边界的距离
    layout->setContentsMargins(0, 0, 0, 0);
    this->setLayout(layout);

    windowLeft = new QWidget();
    windowMid = new QWidget();
    windowRight = new QWidget();

    windowLeft->setFixedWidth(55);
    windowMid->setFixedWidth(226);
    windowRight->setMinimumWidth(670);

    windowLeft->setStyleSheet("QWidget { background-color: rgb(46, 46, 46); }");
    windowMid->setStyleSheet("QWidget { background-color: rgb(247, 247, 247); }");
    windowRight->setStyleSheet("QWidget { background-color: rgb(245, 245, 245); }");

    layout->addWidget(windowLeft);
    layout->addWidget(windowMid);
    layout->addWidget(windowRight);
}

void MainWidget::initLeftWindow()
{
    QVBoxLayout* layout = new QVBoxLayout();
    layout->setSpacing(20);
    layout->setContentsMargins(0, 35, 0, 0);
    windowLeft->setLayout(layout);

    // 添加用户头像
    userAvatar = new QPushButton();
    userAvatar->setFixedSize(37, 37);
    userAvatar->setIconSize(QSize(37, 37));
    // 默认头像移除 避免出现卡顿
    // userAvatar->setIcon(QIcon(":/resource/image/Whitey.jpg"));
    userAvatar->setStyleSheet("QPushButton { background-color: transparent;}");
    layout->addWidget(userAvatar, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加会话标签按钮
    sessionTabBtn = new QPushButton();
    sessionTabBtn->setFixedSize(25, 25);
    sessionTabBtn->setIconSize(QSize(25, 25));
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    sessionTabBtn->setStyleSheet("QPushButton { background-color: transparent; }");
    layout->addWidget(sessionTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加好友标签页按钮
    friendTabBtn = new QPushButton();
    friendTabBtn->setFixedSize(25, 25);
    friendTabBtn->setIconSize(QSize(25, 25));
    friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    friendTabBtn->setStyleSheet("QPushButton { background-color: transparent; }");
    layout->addWidget(friendTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    // 添加好友申请标签页按钮
    applyTabBtn = new QPushButton();
    applyTabBtn->setFixedSize(25, 25);
    applyTabBtn->setIconSize(QSize(22, 22));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
    applyTabBtn->setStyleSheet("QPushButton { background-color: transparent; }");
    layout->addWidget(applyTabBtn, 1, Qt::AlignTop | Qt::AlignHCenter);

    layout->addStretch(20);
}

void MainWidget::initMidWindow()
{
    QGridLayout* layout = new QGridLayout();
    // 距离上方有 20px 的距离，另外三个方向都不要边距
    layout->setContentsMargins(0, 26, 0, 0);
    layout->setSpacing(0);
    windowMid->setLayout(layout);

    QAction* search = new QAction();
    search->setIcon(QIcon(":/resource/image/search.png"));
    searchEdit = new QLineEdit();
    searchEdit->setFixedHeight(25);
    searchEdit->setPlaceholderText("搜索");
    searchEdit->setStyleSheet("QLineEdit { border-radius: 4px; background-color: rgb(226, 226, 226); }"
                              "QLineEdit:focus { background-color: rgb(249, 249, 249);"
                              "border: 1px solid rgb(222, 220, 219); }");
    searchEdit->addAction(search, QLineEdit::LeadingPosition);

    addFriendBtn = new QPushButton();
    addFriendBtn->setFixedSize(25, 25);
    QString style = "QPushButton { border-radius: 5px; background-color: rgb(226, 226, 226); }";
    style += "QPushButton:pressed { background-color: rgb(240, 240, 240); }";
    addFriendBtn->setIcon(QIcon(":/resource/image/cross.png"));
    addFriendBtn->setStyleSheet(style);

    sessionFriendArea = new SessionFriendArea();

    // 为了更灵活的控制边距，只影响搜索框按钮这一行，不影响下方列表这一行
    // 创建空白的 widget 填充到布局管理器中
    QWidget* spacer1 = new QWidget();
    spacer1->setFixedWidth(10);
    QWidget* spacer2 = new QWidget();
    spacer2->setFixedWidth(10);
    QWidget* spacer3 = new QWidget();
    spacer3->setFixedWidth(13);
    QWidget* spacer4 = new QWidget();
    spacer4->setFixedHeight(12);

    layout->addWidget(spacer1, 0, 0);
    layout->addWidget(searchEdit, 0, 1);
    layout->addWidget(spacer2, 0, 2);
    layout->addWidget(addFriendBtn, 0, 3);
    layout->addWidget(spacer3, 0, 4);
    layout->addWidget(spacer4, 1, 0);
    layout->addWidget(sessionFriendArea, 2, 0, 1, 5);
}

void MainWidget::initRightWindow()
{
    // 1. 创建右侧窗口的布局管理器
    QVBoxLayout* vlayout = new QVBoxLayout();
    vlayout->setSpacing(0);
    vlayout->setContentsMargins(0, 0, 0, 0);
    vlayout->setAlignment(Qt::AlignTop);
    windowRight->setLayout(vlayout);

    // 2. 创建上方标题栏
    QWidget* titleWidget = new QWidget();
    titleWidget->setFixedHeight(64);
    titleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    titleWidget->setObjectName("titleWidget");
    titleWidget->setStyleSheet("#titleWidget { border-bottom: 1px solid rgb(231, 231, 231); "
                               "border-left: 1px solid rgb(214, 214, 214)}");
    vlayout->addWidget(titleWidget);

    // 3. 给标题栏，添加标题 label 和 一个按钮
    QHBoxLayout* hlayout = new QHBoxLayout();
    hlayout->setSpacing(0);
    hlayout->setContentsMargins(20, 0, 10, 0);
    titleWidget->setLayout(hlayout);

    sessionTitleLabel = new QLabel();
    sessionTitleLabel->setStyleSheet("QLabel { font-size: 18px; border-bottom: 1px solid rgb(231, 231, 231);}");
#if TEST_UI
    // 测试
    sessionTitleLabel->setText("野原美伢");
#endif
    hlayout->addWidget(sessionTitleLabel);

    extraBtn = new MyPushButton(":/resource/image/more.png", ":/resource/image/more_active.png",
                                            ":/resource/image/more_enter.png");
    extraBtn->setFixedSize(25, 25);
    extraBtn->setIconSize(QSize(25, 25));
    extraBtn->setStyleSheet("QPushButton { border: none; background-color: rgb(245, 245, 245); }");
    hlayout->addWidget(extraBtn);

    // 4. 添加消息展示区
    messageShowArea = new MessageShowArea();
    vlayout->addWidget(messageShowArea);

    QFrame *line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setStyleSheet("QFrame { color: rgb(236, 236, 236); }");
    line->setFixedHeight(2); // 设置横线的高度，可以根据需要调整

    vlayout->addWidget(line);

    // 5. 添加消息编辑区
    messageEditArea = new MessageEditArea();
    vlayout->addWidget(messageEditArea, 0, Qt::AlignBottom);
}

void MainWidget::initSignalSlot()
{
    model::DataCenter* dataCenter = model::DataCenter::getInstance();

    ///////////////////////////////////////////
    /// 连接信号槽，处理标签页按钮切换的问题
    ///////////////////////////////////////////
    connect(sessionTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToSession);
    connect(friendTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToFriend);
    connect(applyTabBtn, &QPushButton::clicked, this, &MainWidget::switchTabToApply);

    ///////////////////////////////////////////
    /// 点击自己的头像，弹出对话框显示个人主页
    ///////////////////////////////////////////
    connect(userAvatar, &QPushButton::clicked, this, [=](){
        SelfInfoWidget* selfInfoWidget = new SelfInfoWidget(this);
        selfInfoWidget->exec();  // 模态对话框
    });

    ///////////////////////////////////////////
    /// 点击会话详情按钮，弹出会话详情窗口
    ///////////////////////////////////////////
    connect(extraBtn, &QPushButton::clicked, this, [=](){
        // 判断单聊还是群聊
// #if TEST_GROUP_SESSION_DETAIL
//         bool isSingleChat = false;
// #else
//         bool isSingleChat = true;
// #endif
        // 获取当前会话详情 通过会话中的 userId 属性
        ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionById(dataCenter->getCurrentChatSessionId());
        if (chatSessionInfo == nullptr)
        {
            LOG("当前会话不存在, 无法弹出会话详情对话框");
            return;
        }
        bool isSingleChat = chatSessionInfo->userId != "";

        if (isSingleChat)
        {
            // 单聊
            UserInfo* userInfo = dataCenter->findFriendById(chatSessionInfo->userId);
            if (userInfo == nullptr)
            {
                LOG("单聊会话对应的用户不存在, 无法弹出会话详情窗口");
                return;
            }
            SessionDetailWidget* sessionDetailWidget = new SessionDetailWidget(this, *userInfo);
            sessionDetailWidget->exec();
        }
        else
        {
            GroupSessionDetailWidget* groupSessionDetailWidget = new GroupSessionDetailWidget(this);
            groupSessionDetailWidget->exec();
        }
    });

    ///////////////////////////////////////////
    /// 点击添加好友按钮，弹出添加好友窗口
    ///////////////////////////////////////////
    connect(addFriendBtn, &QPushButton::clicked, this, [=](){
        AddFriendDialog* addFriendDialog = new AddFriendDialog(this);
        addFriendDialog->exec();
    });

    ///////////////////////////////////////////
    /// 修改搜索框内容，弹出添加好友对话框
    ///////////////////////////////////////////
    connect(searchEdit, &QLineEdit::textEdited, this, [=](){
        // 取出当前输入框的内容
        const QString& searchKey = searchEdit->text();
        AddFriendDialog* addFriendDialog = new AddFriendDialog(this);
        addFriendDialog->setSearchKey(searchKey);
        searchEdit->setText("");
        addFriendDialog->exec();
    });

    ///////////////////////////////////////////
    /// 获取个人信息
    ///////////////////////////////////////////
    // 获取网络数据
    connect(dataCenter, &DataCenter::getMyselfDone, this, [=](){
        // 从 DataCenter 中拿到响应结果的 myself ，把里面的头像取出来显示到界面上
        auto myself = dataCenter->getMyself();
        userAvatar->setIcon(myself->avatar);
    });
    dataCenter->getMyselfAsync();

    ///////////////////////////////////////////
    /// 获取好友列表
    ///////////////////////////////////////////

    loadFriendList();

    ///////////////////////////////////////////
    /// 获取会话列表
    ///////////////////////////////////////////

    loadSessionList();

    ///////////////////////////////////////////
    /// 获取好友申请列表
    ///////////////////////////////////////////

    loadApplyList();

    ///////////////////////////////////////////
    /// 处理修改头像
    ///////////////////////////////////////////

    connect(dataCenter, &DataCenter::changeAvatarDone, this, [=](){
        UserInfo* myself = dataCenter->getMyself();
        userAvatar->setIcon(myself->avatar);
    });

    ///////////////////////////////////////////
    /// 处理删除好友
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::deleteFriendDone, this, [=](){
        this->updateFriendList();
        this->updateChatSessionList();
        LOG("删除好友完成");
    });

    connect(dataCenter, &DataCenter::clearCurrentSession, this, [=](){
        sessionTitleLabel->setText("");
        messageShowArea->clear();
        dataCenter->setCurrentChatSessionId("");
        LOG("清空当前会话完成");
    });

    ///////////////////////////////////////////
    /// 处理添加好友
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::addFriendApplyDone, this, [=](){
        Toast::showMessage("好友申请已发送");
    });

    ///////////////////////////////////////////
    /// 处理添加好友申请推送数据
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::receiveFriendApplyDone, this, [=](){
        this->updateApplyList();
        Toast::showMessage("收到新的好友申请");
    });

    ///////////////////////////////////////////
    /// 同意好友申请
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::acceptFriendApplyDone, this, [=](){
        this->updateApplyList();
        this->updateFriendList();
        Toast::showMessage("好友已经添加完成");
    });

    ///////////////////////////////////////////
    /// 拒绝好友申请
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::rejectFriendApplyDone, this, [=](){
        this->updateApplyList();
        Toast::showMessage("好友申请已经拒绝");
    });


    ///////////////////////////////////////////
    /// 处理好友申请结果的推送数据
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::receiveFriendProcessDone, this, [=](const QString& nickname,
                                                                        bool agree){
        if (agree)
        {
            this->updateApplyList();
            Toast::showMessage(nickname + "同意你的好友申请");
        }
        else
        {
            Toast::showMessage(nickname + "拒绝你的好友申请");
        }
    });


    ///////////////////////////////////////////
    /// 处理响应创建群聊的信号
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::createGroupChatSessionDone, this, [=](){
        Toast::showMessage("创建群聊会话请求已发送!");
    });

    ///////////////////////////////////////////
    /// 处理创建会话的推送数据
    ///////////////////////////////////////////
    connect(dataCenter, &DataCenter::receiveSessionCreateDone, this, [=](){
        this->updateChatSessionList();
        Toast::showMessage("您被拉入新的群聊中!");
    });

}

void MainWidget::initWebsocket()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    dataCenter->initWebsocket();
}

void MainWidget::switchTabToSession()
{
    // 1.记录当前切换到了哪个标签页
    activeTab = SESSION_LIST;
    // 2. 调整图标显示情况，把会话的按钮图标设为 active，另外两个图标设为 inactive
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
    friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
    // 3.在主窗口的中间部分，加载出会话列表数据
    this->loadSessionList();
}

void MainWidget::switchTabToFriend()
{
    // 1.记录当前切换到了哪个标签页
    activeTab = FRIEND_LIST;
    // 2. 调整图标显示情况，把会话的按钮图标设为 active，另外两个图标设为 inactive
    friendTabBtn->setIcon(QIcon(":/resource/image/friend_active.png"));
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
    // 3.在主窗口的中间部分，加载出会话列表数据
    this->loadFriendList();
}

void MainWidget::switchTabToApply()
{
    // 1.记录当前切换到了哪个标签页
    activeTab = APPLY_LIST;
    // 2. 调整图标显示情况，把会话的按钮图标设为 active，另外两个图标设为 inactive
    applyTabBtn->setIcon(QIcon(":/resource/image/apply_active.png"));
    friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
    sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
    // 3.在主窗口的中间部分，加载出会话列表数据
    this->loadApplyList();
}

void MainWidget::loadSessionList()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    if (dataCenter->getChatSessionList() != nullptr)
    {
        // 从内存列表中加载数据
        updateChatSessionList();
    }
    else
    {
        // 通过网络来加载数据
        connect(dataCenter, &DataCenter::getChatSessionListDone,
                this, &MainWidget::updateChatSessionList, Qt::UniqueConnection);
        dataCenter->getChatSessionListAsync();
    }
}

void MainWidget::loadFriendList()
{
    // 好友列表数据在 DataCenter 中存储
    // 首先需要判定 DataCenter 中是否已经有数据了，如果有数据 直接加载本地的数据
    // 如果没有数据 从服务器中获取
    DataCenter* dataCenter = DataCenter::getInstance();
    if (dataCenter->getFriendList() != nullptr)
    {
        // 从内存列表中加载数据
        updateFriendList();
    }
    else
    {
        // 通过网络来加载数据
        connect(dataCenter, &DataCenter::getFriendListDone,
                this, &MainWidget::updateFriendList, Qt::UniqueConnection);
        dataCenter->getFriendListAsync();
    }
}

// 加载好友申请列表
void MainWidget::loadApplyList()
{
    // 好友申请列表数据在 DataCenter 中存储
    // 首先需要判定 DataCenter 中是否已经有数据了，如果有数据 直接加载本地的数据
    // 如果没有数据 从服务器中获取
    DataCenter* dataCenter = DataCenter::getInstance();
    if (dataCenter->getApplyList() != nullptr)
    {
        // 从内存列表中加载数据
        updateApplyList();
    }
    else
    {
        // 通过网络来加载数据
        connect(dataCenter, &DataCenter::getApplyListDone,
                this, &MainWidget::updateApplyList, Qt::UniqueConnection);
        dataCenter->getApplyListAsync();
    }
}

void MainWidget::updateFriendList()
{
    if (activeTab != FRIEND_LIST)
        return;

    DataCenter* dataCenter = DataCenter::getInstance();
    QList<UserInfo>* friendList = dataCenter->getFriendList();

    // 清空一下之前界面上的数据
    sessionFriendArea->clear();

    // 遍历好友列表 添加到界面上
    for (const auto& f : *friendList)
    {
        sessionFriendArea->addItem(FriendItemType, f.userId, f.avatar, f.nickname, f.description);
    }
}

void MainWidget::updateChatSessionList()
{
    if (activeTab != SESSION_LIST)
        return;

    DataCenter* dataCenter = DataCenter::getInstance();
    QList<ChatSessionInfo>* chatSessionList = dataCenter->getChatSessionList();

    // 清空一下之前界面上的数据
    sessionFriendArea->clear();

    // 遍历好友列表 添加到界面上
    for (const auto& c : *chatSessionList)
    {
        if (c.lastMessage.messageType == TEXT_TYPE)
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, c.lastMessage.content);
        else if (c.lastMessage.messageType == IMAGE_TYPE)
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[图片]");
        else if (c.lastMessage.messageType == FILE_TYPE)
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[文件]");
        else if (c.lastMessage.messageType == SPEECH_TYPE)
            sessionFriendArea->addItem(SessionItemType, c.chatSessionId, c.avatar, c.chatSessionName, "[语音]");
        else
            LOG("错误的消息类型! messageType = ") << c.lastMessage.messageType;
    }
}

void MainWidget::updateApplyList()
{
    if (activeTab != APPLY_LIST)
        return;

    DataCenter* dataCenter = DataCenter::getInstance();
    QList<UserInfo>* applyList = dataCenter->getApplyList();

    // 清空一下之前界面上的数据
    sessionFriendArea->clear();

    // 遍历好友列表 添加到界面上
    for (const auto& u : *applyList)
    {
        sessionFriendArea->addItem(ApplyItemType, u.userId, u.avatar, u.nickname, "");
    }
}

void MainWidget::loadRecentMessage(const QString &chatSessionId)
{
    DataCenter* dataCenter = DataCenter::getInstance();
    if (dataCenter->getRecentMessageList(chatSessionId) != nullptr)
    {
        // 从本地中加载数据
        updateRecentMessage(chatSessionId);
    }
    else
    {
        // 通过网络来加载数据
        connect(dataCenter, &DataCenter::getRecentMessageListDone,
                this, &MainWidget::updateRecentMessage, Qt::UniqueConnection);
        dataCenter->getRecentMessageListAsync(chatSessionId, true);
    }
}

void MainWidget::updateRecentMessage(const QString &chatSessionId)
{
    // 1. 拿到该会话的最近消息列表
    DataCenter* dataCenter = DataCenter::getInstance();
    auto* recentMessageList = dataCenter->getRecentMessageList(chatSessionId);

    // 2. 清空一下之前界面上的数据
    messageShowArea->clear();

    // 3. 使用头插
    for (int i = recentMessageList->size() - 1; i >= 0; --i)
    {
        const Message& message = recentMessageList->at(i);
        bool isLeft = message.sender.userId != dataCenter->getMyself()->userId;
        messageShowArea->addFrontMessage(isLeft, message);
    }

    // 4. 设置会话标题
    ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionById(chatSessionId);
    if (chatSessionId != nullptr)
    {
        sessionTitleLabel->setText(chatSessionInfo->chatSessionName);
    }

    // 5. 保存当前选中的会话是哪个
    dataCenter->setCurrentChatSessionId(chatSessionId);

    // 6. 自动滚动到末尾
    messageShowArea->scrollToEnd();
}

void MainWidget::switchSession(const QString &userId)
{
    // 1. 在会话列表中 找到对应的会话元素
    DataCenter* dataCenter = DataCenter::getInstance();
    ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionByUserId(userId);
    if (chatSessionInfo == nullptr)
    {
        // 每个好友都会有对应的会话
        // 添加好友的时候，就创建会话
        LOG("[严重错误] 当前选中的好友, 对应的会话不存在!");
        return;
    }

    // 2. 把选中的会话置顶 把这个会话信息放到整个会话列表的第一个位置
    dataCenter->topChatSessionInfo(*chatSessionInfo);

    // 3. 切换到会话列表标签页
    switchTabToSession();

    // 4. 加载会话列表的历史消息
    sessionFriendArea->clickItem(0);

    // 5. 自动滚动到顶部
    sessionFriendArea->scrollToBegin();
}

MessageShowArea *MainWidget::getMessageShowArea()
{
    return messageShowArea;
}
